package com.hk.core.authentication.security.reactive.filter;

import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.function.Function;

/**
 * 将Spring security reactive 的登录用户注入到 spring security web中,
 * 因为reactive 不支持jpa（可以使用 r2dbc）,在使用审计功能时,reactive api 获取不到登录的用户信息
 * <p>
 * 注入SecurityContext过滤器
 * <p>
 * 需要将此 过滤器添加到 SecurityWebFilterChain 过滤器链中:
 *
 * <pre class="code">
 *      &#064;Bean
 *      public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 *          http.addFilterBefore(new SecurityContextFilter(), SecurityWebFiltersOrder.LAST)
 *      }
 * </pre>
 *
 * @author Kevin
 * @date 2022-07-06 20:39
 */
public class SecurityContextFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return ReactiveSecurityContextHolder.getContext()
                .defaultIfEmpty(SecurityContextHolder.getContext())//没有也注入一个，确保流程能继续
                .flatMap((Function<SecurityContext, Mono<Void>>) securityContext -> {
                    SecurityContextHolder.setContext(securityContext);
                    return chain.filter(exchange);
                });
    }
}
